package top.jle.spring.basic.config;

import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.support.config.FastJsonConfig;
import com.alibaba.fastjson2.support.spring6.webservlet.view.FastJsonJsonView;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import jakarta.annotation.Resource;
import lombok.NonNull;
import org.apache.commons.collections4.CollectionUtils;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.TransportMode;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.*;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import top.jle.spring.basic.fis.InterceptorRegistryCustomizer;
import top.jle.spring.basic.interceptor.GlobalInterceptor;
import top.jle.spring.basic.sensitive.SensitiveValueFilter;
import top.jle.spring.basic.util.JWTHandler;

import java.nio.charset.StandardCharsets;
import java.util.List;

@Order(10)
@Configuration
@ComponentScan({"top.jle.spring.basic.api","top.jle.spring.basic.aspect"})
@EnableConfigurationProperties({URLTrackingProperties.class,WebProperties.class})
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private WebProperties webProperties;
    @Autowired(required = false)
    private List<InterceptorRegistryCustomizer> interceptorRegistryCustomizers;
    @Autowired
    private Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder;
    @Bean
    @ConditionalOnProperty(prefix = "jle.spring.web.sensitive-config",value = "enable",havingValue = "true",matchIfMissing = true)
    @Order(-1)
    public SensitiveValueFilter sensitiveValueFilter(){
        return new SensitiveValueFilter(webProperties.getSensitiveConfig());
    }
    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        return new InternalResourceViewResolver();
    }

    @Override
    public void addInterceptors(@NonNull InterceptorRegistry registry) {
        if (webProperties.getAuthConfig().isEnable()) {
            registry.addInterceptor(globalInterceptor()).excludePathPatterns("/swagger**/**","/**/api-docs/**");
        }
        if(CollectionUtils.isNotEmpty(interceptorRegistryCustomizers)){
            interceptorRegistryCustomizers.forEach(customizer -> customizer.customize(registry));
        }
    }
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.clear();
        converters.add(new MappingJackson2HttpMessageConverter(jackson2ObjectMapperBuilder.build()));
        converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
        converters.add(new ResourceHttpMessageConverter());
        converters.add(new ByteArrayHttpMessageConverter());
        converters.add(new ResourceRegionHttpMessageConverter());
    }
    @Bean
    public FastJsonConfig fastJsonConfig(){
        FastJsonConfig config = new FastJsonConfig();
        config.setWriterFeatures(JSONWriter.Feature.WriteLongAsString,JSONWriter.Feature.WriteEnumsUsingName,JSONWriter.Feature.WriteNullStringAsEmpty,JSONWriter.Feature.WriteMapNullValue,JSONWriter.Feature.WriteNullListAsEmpty, JSONWriter.Feature.PrettyFormat);
        if (webProperties.getSensitiveConfig().isEnable()) {
            config.setWriterFilters(sensitiveValueFilter());
        }
        return config;
    }
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        FastJsonJsonView fastJsonJsonView = new FastJsonJsonView();
        fastJsonJsonView.setFastJsonConfig(fastJsonConfig());
        registry.enableContentNegotiation(fastJsonJsonView);
    }
    @Bean
    public RedissonAutoConfigurationCustomizer redissonAutoConfigurationCustomizer(){
        return configuration -> {
            configuration.setKeepPubSubOrder(true);
            configuration.setCodec(JsonJacksonCodec.INSTANCE);
            configuration.setThreads(0);
            configuration.setNettyThreads(0);
            configuration.setTransportMode(TransportMode.NIO);
        };
    }
    @Bean
    public JWTHandler jwtHandler(){
        return new JWTHandler(webProperties.getAuthConfig());
    }
    @Bean
    @Order(-1)
    @ConditionalOnProperty(prefix = "jle.spring.web.auth-config",value = "enable",havingValue = "true",matchIfMissing = true)
    public GlobalInterceptor globalInterceptor(){
        return new GlobalInterceptor(webProperties.getAuthConfig());
    }
}
